//
//  GLView.swift
//  functional
//
//  Created by LimitLiu on 2019/2/18.
//  Copyright © 2019 LimitLiu. All rights reserved.
//

import UIKit

class GLView: UIView {
    private var context: EAGLContext!
    private var display: CADisplayLink!
    
    private var colorBuffer: GLuint = 0
    private var frameBuffer: GLuint = 0
    private var vertexBuffer: GLuint = GLuint()
    private var gpuOutputBuffer: GLuint = 0

    private var glLayer: CAEAGLLayer {
        return layer as! CAEAGLLayer
    }
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        setup()
        if setupColorBuffer() {
            setupFrameBuffer()
        }
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    deinit {
        if EAGLContext.current() == context {
            EAGLContext.setCurrent(nil)
        }
        if colorBuffer != 0 {
            glDeleteRenderbuffers(1, &colorBuffer)
        }
        if frameBuffer != 0 {
            glDeleteFramebuffers(1, &frameBuffer)
        }
        if (display != nil) {
            display.invalidate()
        }
    }
    
    override class var layerClass: AnyClass {
        return CAEAGLLayer.self
    }
}

extension GLView {
    override func didMoveToSuperview() {
        super.didMoveToSuperview()
        if (superview != nil) {
            display = CADisplayLink(target: self, selector: #selector(self.render))
            display.add(to: RunLoop.main, forMode: .common)
        } else {
            display.invalidate()
            display = nil
        }
        
    }
    
    private func setup() -> Void {
        guard let c = EAGLContext(api: .openGLES3) else {
            fatalError("Failed to create context")
        }
        context = c
        
        if (!EAGLContext.setCurrent(context)) {
            fatalError("Failed to set EAGLContext")
        }
        
        glLayer.isOpaque = true
        glLayer.contentsScale = UIScreen.main.scale
        
    }
    
    private func setupColorBuffer() -> Bool {
        glGenRenderbuffers(1, &colorBuffer)
        glBindRenderbuffer(GLenum(GL_RENDERBUFFER), colorBuffer)
        return context.renderbufferStorage(Int(GL_RENDERBUFFER), from: glLayer)
    }
    
    private func setupFrameBuffer() -> Void {
        glGenFramebuffers(1, &frameBuffer)
        glBindFramebuffer(GLenum(GL_FRAMEBUFFER), frameBuffer)
        glFramebufferRenderbuffer(GLenum(GL_FRAMEBUFFER), GLenum(GL_COLOR_ATTACHMENT0), GLenum(GL_RENDERBUFFER), frameBuffer)
    }
    
    @objc open func render() {
        glClearColor(0.3, 0.0, 0.3, 1.0)
        glClear(GLbitfield(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT))

        glViewport(0, 0, GLsizei(bounds.size.width), GLsizei(bounds.size.height))
        context.presentRenderbuffer(Int(GL_RENDERBUFFER))
    }
    
}
